﻿using System;
using System.Collections.Generic;
using System.Linq;


using Simply.DataTier.Repository.Interface;
using Simply.DataTier.Persistance;
using Simply.Domain;
using Simply.DataTier.Utils;
using Domain;
using Simply.DataTier.Repository.Implementation;
using System.Data;
using System.Data.Linq;

namespace Simply.DataTier.Repository.Implementation
{
    public class ProductEFRepository : BaseEFRepository, IProductRepository
    {
        /*
        #region Cache
        
        #endregion


        private static readonly Func<SimplyDataContext, string, IQueryable<ProductDO>> GetProductsByTypeQuery =
             CompiledQuery.Compile<SimplyDataContext, string, IQueryable<ProductDO>>((ctx, type) => 
                 (from p in ctx.Products
                 where p.ProductCode.Equals(type) 
                 select new ProductDO()
                 {
                     ColorTheme = new ColorThemeDO(){Id = p.ColorTheme.ColorThemeId},
                     CreateDate = p.CreateDate,
                     DefaultDataTemplate = new DataTemplateDO(){Id = p.DefaultDataTemplateId},
                     DesignGroup = new DesignGroupDO(){Id = p.DesignGroupId},
                     Id = p.ProductId,
                     Industry = new IndustryDO(){Id =p.IndustryId},
                     NameEn = p.NameEn,
                     NameRu = p.NameRu,
                     NameAm = p.NameAm,
                     Style = new StyleDO(){ Id = p.StyleId},
                     TypeKey = p.ProductCode
                 })
                 );

        private static readonly Func<SimplyDataContext, ProductFilter, IQueryable<ProductDO>> GetFilteredProductsQuery =
             CompiledQuery.Compile<SimplyDataContext, ProductFilter, IQueryable<ProductDO>>((ctx, filter) => 
                 (from p in ctx.Products
                 where p.ProductType.ProductCode.Equals(filter.ProductType) &&
                    (filter.StyleId != null ? p.StyleId == filter.StyleId : true) &&
                    (filter.ColorId != null ? p.ColorThemeId == filter.ColorId : true) &&
                    (filter.IndustryId != null ? p.IndustryId == filter.IndustryId : true)
                 select new ProductDO()
                 {
                     ColorTheme = new ColorThemeDO(){Id = p.ColorThemeId},
                     CreateDate = p.CreateDate,
                     DefaultDataTemplate = new DataTemplateDO(){Id = p.DefaultDataTemplateId},
                     DesignGroup = new DesignGroupDO(){Id = p.DesignGroupId},
                     Id = p.ProductId,
                     Industry = new IndustryDO(){Id =p.IndustryId},
                     NameEn = p.NameEn,
                     NameRu = p.NameRu,
                     NameAm = p.NameAm,
                     Style = new StyleDO(){ Id = p.StyleId},
                     TypeKey = p.ProductCode
                 }).Skip(filter.SkipItems).Take(filter.TakeItems)
             );

        private static readonly Func<SimplyDataContext, ProductFilter, int> GetFilteredProductsCountQuery =
             CompiledQuery.Compile<SimplyDataContext, ProductFilter, int>((ctx, filter) =>
                    ctx.Products.Count(p => p.ProductType.ProductCode.Equals(filter.ProductType) &&
                                        (filter.StyleId != null ? p.StyleId == filter.StyleId : true) &&
                                        (filter.ColorId != null ? p.ColorThemeId == filter.ColorId : true) &&
                                        (filter.IndustryId != null ? p.IndustryId == filter.IndustryId : true))
                    );
        
/*private static readonly Func<SimplyDataContext, Int32, DataTemplateDO> GetTemplateByIdQuery =
            CompiledQuery.Compile<SimplyDataContext, Int32, DataTemplateDO>((ctx, id) => 
                (from t in ctx.DataTemplates
                where t.DataTemplateId == id
                select new DataTemplateDO()
                    { 
                        Id = t.DataTemplateId,
                        Name = t.LocaleName,
                        Template = new XMLSerializer().DeserializeObject(t.TemplateXML, typeof(InfoTemplate)) as InfoTemplate
                    }).First());

        private static readonly Func<SimplyDataContext, Int64, List<DataTemplateDO>> GetProductTemplatesByIdQuery =
            CompiledQuery.Compile<SimplyDataContext, Int64, List<DataTemplateDO>>((ctx, id) => 
                (from t in ctx.DataTemplates
                    from p in t.Products where p.ProductId == id
                select new DataTemplateDO()
                {
                    Id = t.DataTemplateId,
                    Name = t.LocaleName,
                    Template = new XMLSerializer().DeserializeObject(t.TemplateXML, typeof(InfoTemplate)) as InfoTemplate
                }
                ).ToList());*/
        /*
        private static readonly Func<SimplyDataContext, Int64, ProductDO> GetProductByIdQuery =
            CompiledQuery.Compile<SimplyDataContext, Int64, ProductDO>((ctx, id) =>
                (from p in ctx.Products
                 where p.ProductId == id
                 select new ProductDO() 
                 {
                     ColorTheme = new ColorThemeDO() { Id = p.ColorThemeId },
                     CreateDate = p.CreateDate,
                     DefaultDataTemplate = new DataTemplateDO() { Id = p.DefaultDataTemplateId },
                     DesignGroup = new DesignGroupDO() { Id = p.DesignGroupId },
                     Id = p.ProductId,
                     Industry = new IndustryDO() { Id = p.IndustryId },
                     NameEn = p.NameEn,
                     NameRu = p.NameRu,
                     NameAm = p.NameAm,
                     Style = new StyleDO() { Id = p.StyleId },
                     TypeKey = p.ProductCode
                 }).First()
                );

        

        #region IProductRepository Members

        public List<ProductDO> GetAllProducts(string productType)
        {
            using (SimplyDataContext context = new SimplyDataContext())
            {
                context.ObjectTrackingEnabled = false;
                return GetProductsByTypeQuery.Invoke(context, productType).ToList();
            }
            
        }

        public List<ProductDO> GetFilteredProducts(ProductFilter filter)
        {
           
            using (SimplyDataContext context = new SimplyDataContext())
            {
                context.ObjectTrackingEnabled = false;
                List<ProductDO> products = GetFilteredProductsQuery.Invoke(context, filter).ToList();
                return products;
            }
            
        }

        public int GetFilteredProductsCount(ProductFilter filter)
        {
            using (SimplyDataContext context = new SimplyDataContext())
            {
                context.ObjectTrackingEnabled = false;
                return GetFilteredProductsCountQuery.Invoke(context, filter);
            }
        }

        public DataTemplateDO GetTemplateById(int id)
        {
            using (SimplyDataContext context = new SimplyDataContext())
            {
                context.ObjectTrackingEnabled = false;
                DataTemplateDO templ = (from t in context.DataTemplates
                                      where t.DataTemplateId == id
                                      select new DataTemplateDO()
                                        {
                                            Id = t.DataTemplateId,
                                            NameEn = t.NameEn,
                                            NameRu = t.NameRu,
                                            NameAm = t.NameAm,
                                            Template = (new XMLSerializer()).DeserializeObject(t.TemplateXML, typeof(InfoTemplate)) as InfoTemplate
                                        }).Single();
                return templ;
            }
        }

        public List<DataTemplateDO> GetTemplatesByProductId(long productId)
        {
            using (SimplyDataContext context = new SimplyDataContext())
            {
                context.ObjectTrackingEnabled = false;
                var doList = (from t in context.DataTemplates
                              from p in t.ProductToDataTemplates
                              where p.ProductId == productId
                              select new DataTemplateDO()
                                {
                                    Id = t.DataTemplateId,
                                    NameEn = t.NameEn,
                                    NameRu = t.NameRu,
                                    NameAm = t.NameAm,
                                    Template = new XMLSerializer().DeserializeObject(t.TemplateXML, typeof(InfoTemplate)) as InfoTemplate
                                }).ToList();
                return doList;
            }
            
            /*foreach (var templ in templates)
            {
                doList.Add(new DataTemplateDO()
                {
                    Id = templ.DataTemplateId,
                    Name = templ.LocaleName,
                    Template = new XMLSerializer().DeserializeObject(templ.TemplateXML, typeof(InfoTemplate)) as InfoTemplate
                });
            }*/

            
    /*        //return GetProductTemplatesByIdQuery.Invoke(DbContext, productId);
        }

        public PackageDO GetPackageById(long id)
        {
            using (SimplyDataContext context = new SimplyDataContext())
            {
                context.ObjectTrackingEnabled = false;
                PackageDO dos = (from p in context.Packages
                                 where p.PackageId == id
                                 select new PackageDO()
                                 {
                                     BackFace = p.BackFaceId.HasValue? new BackFaceDO() { Id = p.BackFaceId.Value } : null,
                                     UserId = p.UserId,
                                     Date = p.CreateDate,
                                     Id = p.PackageId,
                                     InfoData = new XMLSerializer().DeserializeObject(p.InfoDataXML, typeof(InfoTemplate)) as InfoTemplate,
                                     PrintMedia = new PrintMediaDO() { Code = p.PrintPricePolicy.PrintMediaCode },
                                     PrintMethod = new PrintMethodDO() { Code = p.PrintPricePolicy.PrintMethodCode },
                                     Product = new ProductDO() { Id = p.ProductId },
                                     Quantity = p.Quantity,
                                     TotalPrice = p.TotalPrice,
                                     FinishingServices = (from f in p.PackageToFinishingPricePolicies 
                                                          select new FinishingServiceDO() 
                                                          { 
                                                              Code = f.FinishingPricePolicy.FinishingServiceCode
                                                          }).ToList(),
                                 }).Single();
                return dos;
            }
            
        }

        public long CreatePackage(PackageDO packageDo)
        {

            using (SimplyDataContext context = new SimplyDataContext())
            {
               
                IBillingRepository rep = new BillingEFRepository();
                Product product = context.Products.Single(m => m.ProductId == packageDo.Product.Id);

                PricePolicyDO pricePolicy = rep.GetProductMinPricePolicy(packageDo.Product.Id, packageDo.Quantity, packageDo.Date);
                PrintPricePolicyDO printPrice = rep.GetPrintMinPricePolicy(product.ProductCode, packageDo.PrintMedia.Code,
                                                packageDo.PrintMethod.Code, packageDo.Quantity, packageDo.Date);

                Package package = new Package();
                package.ProductId = product.ProductId;
                package.PricePolicyId = pricePolicy.Id;
                package.PrintPricePolicyId = printPrice.Id;
                package.Quantity = packageDo.Quantity;
                package.UserId = packageDo.UserId;
                package.CreateDate = packageDo.Date;
                package.InfoDataXML = (new XMLSerializer()).SerializeObject(packageDo.InfoData);
                decimal totalPrice = pricePolicy.Price + printPrice.Price;

                foreach (var finshSrv in packageDo.FinishingServices)
                {
                    FinishingPricePolicyDO finishinPolicy = rep.GetFinishingMinPricePolicy(product.ProductCode, finshSrv.Code, 
                                                            packageDo.PrintMedia.Code, packageDo.Quantity, packageDo.Date);
                   package.PackageToFinishingPricePolicies.Add(new PackageToFinishingPricePolicy()
                   {
                       FinishingPricePolicyId = finishinPolicy.Id,
                   });
                   totalPrice += finishinPolicy.Price;
                }
                package.TotalPrice = totalPrice; 
                
                context.Packages.InsertOnSubmit(package);
                context.SubmitChanges();
                return package.PackageId;
            }
            
            
        }

        public int CreateTemplate(DataTemplateDO template)
        {
            using (var ctx = new SimplyDataContext())
            {
                var entity = new DataTemplate() { 
                    CreateDate = DateTime.Now,
                    NameAm = template.NameAm,
                    NameEn = template.NameEn,
                    NameRu = template.NameRu,
                    TemplateXML = (new XMLSerializer()).SerializeObject(template.Template),
                    
                };
                ctx.DataTemplates.InsertOnSubmit(entity);
                ctx.SubmitChanges();
                return entity.DataTemplateId;
            }
        }

        public IEnumerable<DataTemplateDO> GetAllTemplates(string productType)
        {
            using (var ctx = new SimplyDataContext())
            {
                ctx.ObjectTrackingEnabled = false;

                var res = (from t in ctx.DataTemplates
                           select new DataTemplateDO()
                           {
                               Id = t.DataTemplateId,
                               NameAm = t.NameAm,
                               NameEn = t.NameEn,
                               NameRu = t.NameRu,
                               CreateDate = t.CreateDate,
                               Template = (InfoTemplate)(new XMLSerializer()).DeserializeObject(t.TemplateXML, typeof(InfoTemplate))
                           }).ToList();
                return res;
            }
        }

        public void UpdatePackageFilePath(long packageId, string path)
        {
            using (SimplyDataContext context = new SimplyDataContext())
            {
                Package pack = context.Packages.Single(m => m.PackageId == packageId);
                pack.PrintReadyFilePath = path;
                context.SubmitChanges();
            }
            
        }

        public PrintMediaDO GetDefaultPrintMediaByProductId(long productId)
        {
            using (SimplyDataContext context = new SimplyDataContext())
            {
                context.ObjectTrackingEnabled = false;
                PrintMediaDO defaultMedia = (from p in context.Products
                                             where p.ProductId == productId
                                             select new PrintMediaDO()
                                             {
                                                 Code = p.PrintMedia.MediaCode,
                                                 DefaultPrintMethod = new PrintMethodDO() { Code = p.PrintMedia.DefaultPrintMethodCode },
                                                 DescriptionEn = p.PrintMedia.DescriptionEn,
                                                 DescriptionRu = p.PrintMedia.DescriptionRu,
                                                 DescriptionAm = p.PrintMedia.DescriptionAm,
                                                 Name = p.PrintMedia.Name,
                                                 NameEn = p.PrintMedia.NameEn,
                                                 NameRu = p.PrintMedia.NameRu,
                                                 NameAm = p.PrintMedia.NameAm,
                                                 Type = new PrintMediaTypeDO() { Code = p.PrintMedia.MediaTypeCode },
                                                 Weight = (p.PrintMedia.WeightGr.HasValue ? p.PrintMedia.WeightGr.Value : 0),
                                                 AvailableFrom = p.PrintMedia.AvailableFrom
                                             }).Single();

                return defaultMedia;
            }
            
        }


        public List<PrintMediaDO> GetMediaListByProductId(long productId)
        {
            using (SimplyDataContext context = new SimplyDataContext())
            {
                context.ObjectTrackingEnabled = false;
                List<PrintMediaDO> medias = (from m in context.PrintMedias
                                             from p in m.ProductToPrintMedias
                                             where p.ProductId == productId
                                             select new PrintMediaDO()
                                             {
                                                 Code = m.MediaCode,
                                                 DefaultPrintMethod = new PrintMethodDO() { Code = m.DefaultPrintMethodCode },
                                                 NameEn = m.NameEn,
                                                 NameRu = m.NameRu,
                                                 NameAm = m.NameAm,
                                                 Name = m.Name,
                                                 DescriptionEn = m.DescriptionEn,
                                                 DescriptionRu = m.DescriptionRu,
                                                 DescriptionAm = m.DescriptionAm,
                                                 Type = new PrintMediaTypeDO() { Code = m.MediaTypeCode },
                                                 Weight = (m.WeightGr.HasValue ? m.WeightGr.Value : 0)
                                             }).ToList();
                return medias;
            }
            
        }
        #endregion



        #region IRepository<Product> Members

        public List<ProductDO> GetAll()
        {
            throw new NotImplementedException();
        }

        public ProductDO GetById(long id)
        {
            using (SimplyDataContext context = new SimplyDataContext())
            {
                context.ObjectTrackingEnabled = false;
                return GetProductByIdQuery.Invoke(context, id);
            }
            
        }

        public bool Save(ProductDO entity)
        {
            throw new NotImplementedException();
        }

        public bool Delete(ProductDO entity)
        {
            throw new NotImplementedException();
        }

        #endregion*/
    }
}
